package cn.haoxsf.app.system.controller;

import cn.haoxsf.app.common.api.CommonResult;
import cn.haoxsf.app.common.api.enums.SystemExceptionEnum;
import cn.haoxsf.app.common.api.enums.UserExceptionEnum;

import cn.haoxsf.app.common.apo.repeat.Submit;
import cn.haoxsf.app.common.constant.config.ConstantConfig;
import cn.haoxsf.app.common.exception.BaseException;
import cn.haoxsf.app.common.util.ToolUtil;
import cn.haoxsf.app.common.util.ValidatedUtil;

import cn.haoxsf.app.config.wechat.WxAccountConfig;
import cn.haoxsf.app.system.entity.Member;
import cn.haoxsf.app.system.model.param.LoginParam;
import cn.haoxsf.app.system.model.param.RegisterParam;
import cn.haoxsf.app.system.service.IAuthService;
import cn.haoxsf.app.system.service.IMemberService;
import cn.haoxsf.app.system.service.IRedisService;
import com.alibaba.fastjson.JSONObject;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.log4j.Log4j2;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletResponse;

import java.net.URLEncoder;

import java.util.List;
import java.util.UUID;

/**
 * @program: app
 * @description: 登陆控制器
 * @author: Ele qvbanfm@qq.com
 * @create: 2020-03-23 20:48
 **/
@Controller
@RequestMapping("/user")
@Api(tags = "登陆相关请求", description = "loginController")
@Log4j2
public class loginController {
    @Autowired
    PasswordEncoder passwordEncoder;
    @Autowired
    private IAuthService authService;
    @Autowired
    private IMemberService memberService;
    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Autowired
    private IRedisService redisService;
    @Autowired
    private WxMpService wxMpService;//微信公众平台

    @PostMapping("login")
    @ApiOperation(value = "用户登陆")
    @Submit
    @ResponseBody
    public CommonResult login(HttpServletResponse response, @RequestBody(required = false) @Validated @ApiParam(value = "登陆JSON参数") LoginParam param, BindingResult result) {
        if (ToolUtil.isEmpty(param)) {
            return CommonResult.error(SystemExceptionEnum.VALIDATE_FAILED.getCode(), SystemExceptionEnum.VALIDATE_FAILED.getMsg() + "用户名或者密码为空");
        }
        if (result.hasErrors()) {
            String errorMessage = ValidatedUtil.getErrorMessage(result);
            return CommonResult.error(SystemExceptionEnum.VALIDATE_FAILED.getCode(), errorMessage);
        }
        String loginToken = authService.login(param.getUsername(), param.getPassword());
        response.setHeader(tokenHeader, tokenHead + " " + loginToken);
        return CommonResult.success();
    }

    @GetMapping("/logout")
    @ApiOperation(value = "注销登陆")
    @ResponseBody
    public CommonResult logout() {
        authService.logout();
        redisService.logout(authService.getLoginUser().getUsername());
        return CommonResult.success(SystemExceptionEnum.LOGOUT_IS_OK.getMsg());
    }

    @GetMapping("auth")
    @ApiIgnore
    public String auth(@RequestParam("state") String returnUrl) {
        WxAccountConfig wx = (WxAccountConfig) ConstantConfig.getConstant("wx");
        //1.获取微信
        String url = wxMpService.oauth2buildAuthorizationUrl(
                wx.getAuthUrl() + "/user/auth/userInfo",
                WxConsts.OAuth2Scope.SNSAPI_USERINFO, URLEncoder.encode(returnUrl)
        );
        return "redirect:" + url;
    }

    //获取微信用户详情
    @GetMapping("auth/userInfo")
    @ApiIgnore
    public String getUserInfo(@RequestParam("code") String code, @RequestParam("state") String returnUrl) {
        WxMpUser wxMpUser = null;
        try {
            WxMpOAuth2AccessToken wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
            wxMpUser = wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken, null);
        } catch (WxErrorException e) {
            e.printStackTrace();
            log.error("获取微信用户出错[{}]", e.getMessage());
        }
        //查询是否已经绑定有本地用户
        Member memberByOpenId = memberService.getMemberByOpenId(wxMpUser.getOpenId());
        String sp = wxMpUser.getOpenId() + "," + UUID.randomUUID().toString();//临时密码盐
        String Md5 = DigestUtils.md5Hex(sp);//临时密码
        redisService.setString(Md5, sp, 15);
        if (ToolUtil.isEmpty(memberByOpenId)) {//没有绑定用户
            //临时储存微信用户 有效时间 15分
            redisService.setString(wxMpUser.getOpenId(), JSONObject.toJSONString(wxMpUser), 15);
            return "redirect:" + returnUrl + "?binding=NO&id=" + Md5;
        } else {//已绑定
            return "redirect:" + returnUrl + "?binding=" + Md5;
        }

    }

    //auth2登陆
    @ResponseBody
    @PostMapping("auth/auth2")
    @Submit
    @ApiOperation(value = "用于数据库中是否有微信用户")
    public CommonResult authLogin(HttpServletResponse response, @ApiParam(value = "用于数据库中是否有微信用户=>有->返回登陆token在响应头里，返回的URL格式为?binding=xxx(xxx)为uuid;没有=>不返回响应头，返回的URL格式为?binding=NO&id=xx(xxx)为uuid") @RequestParam(required = false) String uuid) {
        List<Member> memberList;
        String string = redisService.getString(ToolUtil.isEmpty(uuid) ? "e" : uuid);//查询临时加密
        Member memberByOpenId = new Member();//解密查询openid
        if (ToolUtil.isNotEmpty(uuid) && ToolUtil.isNotEmpty(string)) {//解密查询openid
            memberList = memberService.getMemberListByOpenId();
            for (Member member : memberList) {
                if (ToolUtil.isNotEmpty(member.getOpenId())) {
                    if (DigestUtils.md5Hex(string).equals(uuid)) {
                        //已解密
                        memberByOpenId = member;
                        break;
                    }
                }
            }
        }
        if (ToolUtil.isNotEmpty(memberByOpenId.getUsername())) {//已绑定生成登陆token
            String loginToken = authService.authLogin(memberByOpenId.getUsername());
            response.setHeader(tokenHeader, tokenHead + " " + loginToken);
            //删除临时密码盐
            redisService.logout(uuid);
            return CommonResult.success();
        } else {//没有绑定
            return CommonResult.error(UserExceptionEnum.UNBOUND_USER);
        }
    }

    @ResponseBody
    @PostMapping("auth/binding")
    @Submit
    @ApiOperation(value = "用于微信绑定用户")
    public CommonResult bindingUser(HttpServletResponse response, @RequestBody(required = false) @ApiParam(value = "注册JSON参数") @Validated RegisterParam registerParam, BindingResult result) {
        if (result.hasErrors()) {
            String errorMessage = ValidatedUtil.getErrorMessage(result);
            return CommonResult.error(SystemExceptionEnum.VALIDATE_FAILED.getCode(), errorMessage);
        }
        String string = redisService.getString(registerParam.getOpenId());
        if (ToolUtil.isEmpty(string)) {
            return CommonResult.error(SystemExceptionEnum.VALIDATE_FAILED.getCode(), "页面超时！");
        }
        log.info("openid[{}]", string.split(",")[0]);
        Member member = new Member();
        BeanUtils.copyProperties(registerParam, member);
        member.setOpenId(string.split(",")[0]);
        //获取微信用户
        String mpUser = redisService.getString(member.getOpenId());
        if (ToolUtil.isNotEmpty(mpUser)) {
            WxMpUser wxMpUser = JSONObject.parseObject(mpUser, WxMpUser.class);
            member.setNickName(wxMpUser.getNickname());
            member.setAvatar(wxMpUser.getHeadImgUrl());
            try {
                memberService.add(member);//添加用户和绑定微信
            } catch (BaseException be) {//更新绑定微信
                //查询用户
                Member memberByUsername = memberService.getMemberByUsername(member.getUsername());
                if (ToolUtil.isNotEmpty(memberByUsername)) {
                    //密码是是否正确
                    if (passwordEncoder.matches(member.getPassword(), memberByUsername.getPassword())) {
                        //是否是已绑定过
                        if (ToolUtil.isNotEmpty(memberByUsername.getOpenId())) {
                            if (memberByUsername.getOpenId().equals(member.getOpenId())) {
                                throw new BaseException(UserExceptionEnum.OPENID_EXISTS);
                            }
                        }
                        memberService.updateMember(member);
                    } else {
                        throw new BaseException(UserExceptionEnum.NOT_USERS);
                    }
                }
            }

            // 删除临时微信用户
            redisService.logout(wxMpUser.getOpenId());
            // 删除临时密码盐
            redisService.logout(registerParam.getOpenId());
        }
        //生成登陆token
        String loginToken = authService.authLogin(member.getUsername());
        response.setHeader(tokenHeader, tokenHead + " " + loginToken);
        return CommonResult.success();
    }
}
